﻿' Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax

Namespace Microsoft.CodeAnalysis.VisualBasic

    ''' <summary>
    ''' Binder used to bind using blocks. 
    ''' It hosts the variables declared in the resource list (if they are declared).
    ''' </summary>
    Friend NotInheritable Class UsingBlockBinder
        Inherits BlockBaseBinder

        Private ReadOnly _syntax As UsingBlockSyntax
        Private _locals As ImmutableArray(Of LocalSymbol) = Nothing

        Public Sub New(enclosing As Binder, syntax As UsingBlockSyntax)
            MyBase.New(enclosing)

            Debug.Assert(syntax IsNot Nothing)
            _syntax = syntax
        End Sub

        Friend Overrides ReadOnly Property Locals As ImmutableArray(Of LocalSymbol)
            Get
                If _locals.IsDefault Then
                    ImmutableInterlocked.InterlockedCompareExchange(_locals, BuildLocals(), Nothing)
                End If

                Return _locals
            End Get
        End Property

        ' Build a read only array of all the local variables declared By the Using statement.
        ' there can be none or multiple variable declarators with multiple variable names
        Private Function BuildLocals() As ImmutableArray(Of LocalSymbol)
            Dim variableDeclarators = _syntax.UsingStatement.Variables

            If variableDeclarators.Count > 0 Then
                Dim localsBuilder = ArrayBuilder(Of LocalSymbol).GetInstance

                For Each variableDeclarator In variableDeclarators
                    Dim isNotAsNewAndHasInitializer = variableDeclarator.Initializer IsNot Nothing AndAlso
                                                      (variableDeclarator.AsClause Is Nothing OrElse variableDeclarator.AsClause.Kind <> SyntaxKind.AsNewClause)

                    Dim names = variableDeclarator.Names
                    For i = 0 To names.Count - 1
                        Dim name = names(i)

                        ' we'll simply reuse the logic for local variables here (incl. local type inference)

                        ' if this is not an AsNew declaration with multiple names and an initializer (error case), then only use
                        ' the initializer for the last variable.
                        localsBuilder.Add(LocalSymbol.Create(Me.ContainingMember, Me,
                                                             name.Identifier, name, variableDeclarator.AsClause,
                                                             If(isNotAsNewAndHasInitializer AndAlso i = names.Count - 1,
                                                                variableDeclarator.Initializer,
                                                                Nothing),
                                                             LocalDeclarationKind.Using))
                    Next
                Next

                Return localsBuilder.ToImmutableAndFree
            End If

            Return ImmutableArray(Of LocalSymbol).Empty
        End Function
    End Class
End Namespace

